package com.neouton.crm.op.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.neouton.common.entity.ActivitiVO;
import com.neouton.common.util.*;
import com.neouton.crm.approval.entity.ApprovalVO;
import com.neouton.crm.approval.service.IApprovalService;
import com.neouton.crm.dictionary.entity.DictionaryLookupItemVO;
import com.neouton.crm.dictionary.service.IDictionaryService;
import com.neouton.crm.entity.DynamicExcelData;
import com.neouton.crm.entity.SysUserEntity;
import com.neouton.crm.op.entity.SalesOpportunityVO;
import com.neouton.crm.op.mapper.SalesOpportunityBackMapper;
import com.neouton.crm.op.mapper.SalesOpportunityMapper;
import com.neouton.crm.op.service.SalesOpportunityService;
import com.neouton.crm.payRecords.entity.PaymentRecords;
import com.neouton.crm.payRecords.entity.PaymentRequest;
import com.neouton.crm.payRecords.mapper.PaymentRecordsMapper;
import com.neouton.crm.payRecords.mapper.PaymentRequestMapper;
import com.neouton.crm.paymentPlan.entity.PaymentPlan;
import com.neouton.crm.paymentPlan.mapper.PaymentPlanMapper;
import com.neouton.crm.pm.entity.PurchaseOrderVO;
import com.neouton.crm.pm.mapper.PurchaseOrdeMapper;
import com.neouton.crm.pm.mapper.SalesProjectManageMapper;
import com.neouton.crm.pm.service.IInternalPurchaseService;
import com.neouton.crm.pm.service.IPurchaseOrdeService;
import com.neouton.crm.receiptRecords.entity.ReceiptRecords;
import com.neouton.crm.receiptRecords.mapper.ReceiptRecordsMapper;
import com.neouton.crm.refundRecords.entity.RefundRecordsVO;
import com.neouton.crm.refundRecords.mapper.RefundRecordsMapper;
import com.neouton.crm.sales.entity.SalesChangeVO;
import com.neouton.crm.sales.entity.SalesFileRelationVO;
import com.neouton.crm.sales.entity.SalesStageVO;
import com.neouton.crm.sales.mapper.SalesFileRelationMapper;
import com.neouton.crm.sales.mapper.SalesStageMapper;
import com.neouton.crm.sales.service.SalesChangeService;
import com.neouton.crm.transpondEmail.entity.TranspondEmailVO;
import com.neouton.crm.transpondEmail.service.TranspondEmailService;
import com.neouton.feginClient.FeginService;
import com.neouton.feginClient.WorkFlowFeginService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;

import static com.neouton.common.util.EasyExcelUtils.dynamicExport;
import static com.neouton.common.util.EasyExcelUtils.getDataList;

@Service
public class SalesOpportunityServiceImpl implements SalesOpportunityService {
    @Resource
    private WorkFlowFeginService workFlowService;
    @Resource
    private FeginService feginService;
    @Resource
    private SalesOpportunityMapper salesOpportunityMapper;
    @Resource
    private SalesProjectManageMapper salesProjectManageMapper;
    @Resource
    private IDictionaryService dictionaryService;
    @Resource
    private IApprovalService approvalService;
    @Resource
    private SalesStageMapper stageMapper;
    @Resource
    private SalesOpportunityBackMapper opportunityBackMapper;
    @Resource
    private SalesFileRelationMapper fileRelationMapper;
    @Resource
    private SalesChangeService salesChangeService;

    @Resource
    private IPurchaseOrdeService purchaseOrdeService;

    @Resource
    private IInternalPurchaseService internalPurchaseService;

    @Resource
    private RefundRecordsMapper refundRecordsMapper;

    @Resource
    PurchaseOrdeMapper purchaseOrdeMapper;

    @Value("${webSit.web}")
    private String webSitUrl;

    @Resource
    private PaymentPlanMapper paymentPlanMapper;
    @Resource
    private PaymentRecordsMapper paymentRecordsMapper;
    @Resource
    private ReceiptRecordsMapper receiptRecordsMapper;
    @Resource
    private PaymentRequestMapper paymentRequestMapper;
    @Resource
    private TranspondEmailService transpondEmailService;

    @Resource
    private WorkFlowFeginService workFlowFeginService;

    @Override
    public ResponseAPI saveOpportunity(SalesOpportunityVO record, String token) {
        record.setCreator(AuthUtils.getUserId());
//        Integer ownerId = record.getOwner();
        SysUserEntity approvalUser = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
        Integer businessId = this.startSaveOpportunityApproval();
        ApprovalVO approval = approvalService.initApprovalAndLog(businessId, 45, record.getReasonApplication(), "",
                approvalUser.getUserId(),"");
        //之后更新/保存
        record.setApprovalId(approval.getApprovalId());
        // 新建默认审核状态为0，不存在于字典中，意为新建未提交审核状态
        record.setMigrateState(0);
        salesOpportunityMapper.insert(record);
        // 转发人记录
        if (record.getSenderList() != null && !record.getSenderList().isEmpty()){
            TranspondEmailVO transpondEmailVO = new TranspondEmailVO();
            transpondEmailVO.setTodoType(Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
            transpondEmailVO.setTypeId(record.getOpportunityId());
            List<Integer> senderList = new ArrayList<>();
            for (SysUserEntity user:record.getSenderList()) {
                senderList.add(user.getUserId());
            }
            transpondEmailVO.setTranspondUseIdList(senderList);
            transpondEmailService.insertTranspondEmailInfoByType(transpondEmailVO);
        }
        if(AuthUtils.getUserAccount().equals(approvalUser.getAccount())){
            //跳过第一步审批
            this.approveCreateOp(record,token,true);
        }
        Integer userId = AuthUtils.getUserId();
        CompletableFuture.runAsync(() ->
                NoticUtils.pushNotic(record.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                        userId, 0, 45, approvalUser.getUserId(), token));
//        record = salesOpportunityMapper.selectByPrimaryKey(record.getOpportunityId());
//        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(ownerId, token);
//        SysUserEntity user = res.getResult();
////        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("opportunity");
////        String copyForUserEmails = getCopyForUserEmails(copyUserIList);
//        List<SysUserEntity> allUser = salesProjectManageMapper.getUserInformation();
//        String title = "【系统通知】机会点信息创建 - 流程单提醒通知";
//        String msg = "<div><p>" + "尊敬的" + user.getLoginName() + "：</p></div>" +
//                "<div><p style='text-indent: 2em'>您好，您有一个新的机会点创建成功：</p></div>" +
//                "<div><p style='text-indent: 2em'>机会编号：" + record.getOpportunityNumber() + "</p></div>" +
//                "<div><p style='text-indent: 2em'>机会名称：" + record.getOpportunityTheme() + "</p></div>" +
//                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 机会信息管理 - 机会信息 " +
//                "<a href='" + webSitUrl + "/?m=crm&p=salesManage&me=salesOpportunity'>进入</a></p></div>" +
//                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
//                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
//        String ownerEmail = allUser.stream().filter(p -> Objects.equals(p.getUserId(), ownerId)).toList().get(0).getEmail();
//        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(ownerEmail, null, title, msg, token));
//        // 保存机会时会插入一条阶段变更记录
//        SalesStageVO salesStageVO = new SalesStageVO();
//        salesStageVO.setStageClass(Constants.OPPORTUNITY_MODEL_ID);
//        salesStageVO.setSalesRelationId(record.getOpportunityId());
//        salesStageVO.setCreator(record.getCreator());
//        salesStageVO.setCreateDataTime(record.getStageUpdateTime());
//        salesStageVO.setStageStateId(record.getStageStateId());
//        int insertSt = stageMapper.insert(salesStageVO);
//        if (insertOp > 0 && insertSt > 0) {
//            return ResponseAPI.successData(record.getOpportunityId());
//        } else {
//            return ResponseAPI.error("保存失败");
//        }
        return ResponseAPI.successData(record.getOpportunityId());
    }

    /**
     * 机会点保存
     */
    public ResponseAPI updateOpportunityByCreate(SalesOpportunityVO record, String token){
        record.setCreator(AuthUtils.getUserId());
        SysUserEntity approvalUser = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
        Integer businessId = this.startSaveOpportunityApproval();
        ApprovalVO approval = approvalService.initApprovalAndLog(businessId, 45, record.getReasonApplication(), "",
                approvalUser.getUserId(),"");
        //之后更新/保存
        record.setApprovalId(approval.getApprovalId());
        // 新建默认审核状态为0，不存在于字典中，意为新建未提交审核状态
        record.setMigrateState(0);
        opportunityBackMapper.insertBackInfo(record.getOpportunityId());
        salesOpportunityMapper.updateOppByCreate(record);
        // 转发人记录
        if (record.getSenderList() != null && !record.getSenderList().isEmpty()){
            TranspondEmailVO transpondEmailVO = new TranspondEmailVO();
            transpondEmailVO.setTodoType(Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
            transpondEmailVO.setTypeId(record.getOpportunityId());
            List<Integer> senderList = new ArrayList<>();
            for (SysUserEntity user:record.getSenderList()) {
                senderList.add(user.getUserId());
            }
            transpondEmailVO.setTranspondUseIdList(senderList);
            transpondEmailService.insertTranspondEmailInfoByType(transpondEmailVO);
        }
        if(AuthUtils.getUserAccount().equals(approvalUser.getAccount())){
            //跳过第一步审批
            this.approveCreateOp(record,token,true);
        }
        Integer userId = AuthUtils.getUserId();
        CompletableFuture.runAsync(() ->
                NoticUtils.pushNotic(record.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                        userId, 0, 45, approvalUser.getUserId(), token));
        return ResponseAPI.successData(record.getOpportunityId());
    }

    /**
     * 导出机会信息
     *
     * @param response
     * @param list
     * @param token
     * @throws Exception
     */
    @Override
    public void exportOpportunityInfo(HttpServletResponse response, List<SalesOpportunityVO> list, String token) throws Exception {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> statesList = new ArrayList<>();
        statesList.add("opportunityState");
        statesList.add("opportunityStage");
        statesList.add("projectState");
        statesList.add("opportunityApprovalState");
        statesList.add("projectApprovalState");
        statesList.add("warrantyTypes");
        JSONObject userObject = feginService.getUserInfo(token);
        JSONObject jsonObject = feginService.queryDictionaryLookupInfo("crm", statesList);
        List<String> classfiedCode = new ArrayList<>();
        classfiedCode.add("projectType");
        classfiedCode.add("projectClasses");
        classfiedCode.add("projectDifferentId");
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(null, classfiedCode);
        Map<Integer, String> userMap = getUserNameMap(userObject);
        Map<Integer, String> opportunityStateMap = getDictionaryNameByCode("opportunityState", jsonObject);
        Map<Integer, String> opportunityStageMap = getDictionaryNameByCode("opportunityStage", jsonObject);
        Map<Integer, String> projectStateMap = getDictionaryNameByCode("projectState", jsonObject);
        Map<Integer, String> warrantyTypesMap = getDictionaryNameByCode("warrantyTypes", jsonObject);
        Map<Integer, String> opportunityApprovalStateMap = getDictionaryNameByCode("opportunityApprovalState", jsonObject);
        Map<Integer, String> projectApprovalStateMap = getDictionaryNameByCode("projectApprovalState", jsonObject);
        Map<Integer, String> projectDifferentMap = getDictionaryNameByCode("projectDifferentId", listMap);
        Map<Integer, String> projectClassesMap = getDictionaryNameByCode("projectClasses", listMap);
        Map<Integer, String> projectTypeMap = getDictionaryNameByCode("projectType", listMap);
        for (int i = 0; i < list.size(); i++) {
            SalesOpportunityVO opVO = list.get(i);
            opVO.setOpportunityId(i + 1);
            opVO.setProjectClassesName(projectClassesMap.get(opVO.getProjectClasses() + ""));
            opVO.setOwnerName(userMap.get(opVO.getOwner()));
            opVO.setCreatorName(userMap.get(opVO.getCreator()));
            opVO.setProjectStateName(projectStateMap.get(opVO.getProjectState() + ""));
            opVO.setOpportunityStateName(opportunityStateMap.get(opVO.getOpportunityState() + ""));
            opVO.setApproveStateFirstName(projectApprovalStateMap.get(opVO.getApproveStateFirst() + ""));
            opVO.setAuditStateLastName(projectApprovalStateMap.get(opVO.getAuditStateLast() + ""));
            opVO.setWarrantyName(warrantyTypesMap.get(opVO.getWarranty() + ""));
            opVO.setOpportunityPossibilityPercentage(opVO.getOpportunityPossibility() + "%");
            opVO.setStageStateName(opportunityStageMap.get(opVO.getStageStateId() + ""));
            opVO.setStageUpdateTime(opVO.getCreateDataTime()); // 导出时反射未做父类解析，当前字段导出未用，暂时借用
            opVO.setAuditStateName(opportunityApprovalStateMap.get(opVO.getAuditState() + ""));
            opVO.setProjectDifferentName(projectDifferentMap.get(opVO.getProjectDifferentId() + ""));
            opVO.setProjectTypeName(projectTypeMap.get(opVO.getProjectType() + ""));
            opVO.setExpectedAmountValue(new DecimalFormat("0.00").format(Double.parseDouble(opVO.getExpectedAmount() == null ? "0" : opVO.getExpectedAmount().getValue())));
            opVO.setRealTimeProfitMoney(new BigDecimal(opVO.getReturnedMoney()).subtract(new BigDecimal(opVO.getPurchaseMoney())).subtract(new BigDecimal(opVO.getReimburseMoney())).toString());
        }
        this.exportOpportunityInfoExcel(response, list);
    }

    /**
     * 分页查询机会信息
     *
     * @param page
     * @param opportunityVO
     * @param userList
     * @param token
     * @return
     */
    @Override
    public PageUtil<SalesOpportunityVO> queryOpportunity(IPage<SalesOpportunityVO> page, SalesOpportunityVO opportunityVO, List<SysUserEntity> userList, String token) {
        if (opportunityVO.getOrderByProp() != null) {
            if (opportunityVO.getOrderByProp().equals("createDataTime")) {
                opportunityVO.setOrderByProp("creationDate");
            }
            opportunityVO.setOrderByProp(StringUtils.camelToUnderline(opportunityVO.getOrderByProp()));
        }
        IPage<SalesOpportunityVO> iPage = salesOpportunityMapper.queryOpportunity(page, opportunityVO, userList);
        List<SalesOpportunityVO> list = iPage.getRecords();
        if (list != null && !list.isEmpty()) {
            List<SalesOpportunityVO> voList = salesOpportunityMapper.queryOpportunity(opportunityVO, userList);
            BigDecimal expectedAmountPage = new BigDecimal(0);
            BigDecimal expectedAmountTotal = new BigDecimal(0);
            BigDecimal projectManageMoneyPage = new BigDecimal(0);
            BigDecimal projectManageMoneyTotal = new BigDecimal(0);
            BigDecimal projectExpectMoneyPage = new BigDecimal(0);
            BigDecimal projectExpectMoneyTotal = new BigDecimal(0);
            BigDecimal returnedMoneyPage = new BigDecimal(0);
            BigDecimal returnedMoneyTotal = new BigDecimal(0);
            BigDecimal invoicedMoneyPage = new BigDecimal(0);
            BigDecimal invoicedMoneyTotal = new BigDecimal(0);
            BigDecimal paymentedMoneyPage = new BigDecimal(0);
            BigDecimal paymentedMoneyTotal = new BigDecimal(0);

            BigDecimal purchaseMoneyPage = new BigDecimal(0);
            BigDecimal purchaseMoneyTotal = new BigDecimal(0);
            BigDecimal reimburseMoneyPage = new BigDecimal(0);
            BigDecimal reimburseMoneyTotal = new BigDecimal(0);
            BigDecimal projectMoneyPage = new BigDecimal(0);
            BigDecimal projectMoneyTotal = new BigDecimal(0);

            BigDecimal refundMoneyPage = new BigDecimal(0);
            BigDecimal refundMoneyTotal = new BigDecimal(0);
            BigDecimal internalPurchaseMoneyPage = new BigDecimal(0);
            BigDecimal internalPurchaseMoneyTotal = new BigDecimal(0);
            BigDecimal projectWarrantyDepositPage = new BigDecimal(0);
            BigDecimal projectWarrantyDepositTotal = new BigDecimal(0);

            BigDecimal collectTicketedMoneyPage = new BigDecimal(0);
            BigDecimal collectTicketedMoneyTotal = new BigDecimal(0);

            BigDecimal warrantyDepositPage = new BigDecimal(0);
            BigDecimal warrantyDepositTotal = new BigDecimal(0);
            for (SalesOpportunityVO item : list) {
                expectedAmountPage = expectedAmountPage.add(new BigDecimal(item.getExpectedAmount().getValue()));
            }
            for (SalesOpportunityVO item : voList) {
                expectedAmountTotal = expectedAmountTotal.add(new BigDecimal(item.getExpectedAmount().getValue()));
            }
            for (SalesOpportunityVO item : list) {
                if( null != item.getProjectManageMoney()){
                    projectManageMoneyPage = projectManageMoneyPage.add(new BigDecimal(item.getProjectManageMoney().getValue()));
                }
                projectExpectMoneyPage = projectExpectMoneyPage.add(new BigDecimal(item.getProjectExpectMoney()));
                returnedMoneyPage = returnedMoneyPage.add(new BigDecimal(item.getReturnedMoney()));
                purchaseMoneyPage = purchaseMoneyPage.add(new BigDecimal(item.getPurchaseMoney()));
                reimburseMoneyPage = reimburseMoneyPage.add(new BigDecimal(item.getReimburseMoney()));
                projectMoneyPage = projectMoneyPage.add(new BigDecimal(item.getProjectMoney()));
                invoicedMoneyPage = invoicedMoneyPage.add(new BigDecimal(item.getInvoicedMoney()));
                paymentedMoneyPage = paymentedMoneyPage.add(new BigDecimal(item.getPaymentedMoney()));
                collectTicketedMoneyPage = collectTicketedMoneyPage.add(new BigDecimal(item.getCollectTicketedMoney()));
                warrantyDepositPage = warrantyDepositPage.add(new BigDecimal(item.getWarrantyDeposit()));
                refundMoneyPage = refundMoneyPage.add(new BigDecimal(item.getRefundMoney()));
                internalPurchaseMoneyPage = internalPurchaseMoneyPage.add(new BigDecimal(item.getInternalPurchaseMoney()));
                projectWarrantyDepositPage = projectWarrantyDepositPage.add(new BigDecimal(item.getProjectWarrantyDeposit()));
            }
            for (SalesOpportunityVO item : voList) {
                if( null != item.getProjectManageMoney()){
                    projectManageMoneyTotal = projectManageMoneyTotal.add(new BigDecimal(item.getProjectManageMoney().getValue()));
                }
                projectExpectMoneyTotal = projectExpectMoneyTotal.add(new BigDecimal(item.getProjectExpectMoney()));
                returnedMoneyTotal = returnedMoneyTotal.add(new BigDecimal(item.getReturnedMoney()));
                invoicedMoneyTotal = invoicedMoneyTotal.add(new BigDecimal(item.getInvoicedMoney()));
                paymentedMoneyTotal = paymentedMoneyTotal.add(new BigDecimal(item.getPaymentedMoney()));
                collectTicketedMoneyTotal = collectTicketedMoneyTotal.add(new BigDecimal(item.getCollectTicketedMoney()));
                purchaseMoneyTotal = purchaseMoneyTotal.add(new BigDecimal(item.getPurchaseMoney()));
                reimburseMoneyTotal = reimburseMoneyTotal.add(new BigDecimal(item.getReimburseMoney()));
                projectMoneyTotal = projectMoneyTotal.add(new BigDecimal(item.getProjectMoney()));
                warrantyDepositTotal = warrantyDepositTotal.add(new BigDecimal(item.getWarrantyDeposit()));
                refundMoneyTotal = refundMoneyTotal.add(new BigDecimal(item.getRefundMoney()));
                internalPurchaseMoneyTotal = internalPurchaseMoneyTotal.add(new BigDecimal(item.getInternalPurchaseMoney()));
                projectWarrantyDepositTotal = projectWarrantyDepositTotal.add(new BigDecimal(item.getProjectWarrantyDeposit()));
            }
            list.get(0).setExpectedAmountPage(String.valueOf(expectedAmountPage));
            list.get(0).setExpectedAmountTotal(String.valueOf(expectedAmountTotal));
            list.get(0).setProjectManageMoneyPage(String.valueOf(projectManageMoneyPage));
            list.get(0).setProjectManageMoneyTotal(String.valueOf(projectManageMoneyTotal));
            list.get(0).setProjectExpectMoneyPage(String.valueOf(projectExpectMoneyPage));
            list.get(0).setProjectExpectMoneyTotal(String.valueOf(projectExpectMoneyTotal));
            list.get(0).setReturnedMoneyPage(String.valueOf(returnedMoneyPage));
            list.get(0).setReturnedMoneyTotal(String.valueOf(returnedMoneyTotal));
            list.get(0).setInvoicedMoneyPage(String.valueOf(invoicedMoneyPage));
            list.get(0).setInvoicedMoneyTotal(String.valueOf(invoicedMoneyTotal));
            list.get(0).setPaymentedMoneyPage(String.valueOf(paymentedMoneyPage));
            list.get(0).setPaymentedMoneyTotal(String.valueOf(paymentedMoneyTotal));
            list.get(0).setCollectTicketedMoneyPage(String.valueOf(collectTicketedMoneyPage));
            list.get(0).setCollectTicketedMoneyTotal(String.valueOf(collectTicketedMoneyTotal));
            list.get(0).setPurchaseMoneyPage(String.valueOf(purchaseMoneyPage));
            list.get(0).setPurchaseMoneyTotal(String.valueOf(purchaseMoneyTotal));
            list.get(0).setReimburseMoneyPage(String.valueOf(reimburseMoneyPage));
            list.get(0).setReimburseMoneyTotal(String.valueOf(reimburseMoneyTotal));
            list.get(0).setProjectMoneyPage(String.valueOf(projectMoneyPage));
            list.get(0).setProjectMoneyTotal(String.valueOf(projectMoneyTotal));
            list.get(0).setWarrantyDepositPage(String.valueOf(warrantyDepositPage));
            list.get(0).setWarrantyDepositTotal(String.valueOf(warrantyDepositTotal));
            list.get(0).setInternalPurchaseMoneyTotal(String.valueOf(internalPurchaseMoneyTotal));
            list.get(0).setInternalPurchaseMoneyPage(String.valueOf(internalPurchaseMoneyPage));
            list.get(0).setProjectWarrantyDepositTotal(String.valueOf(projectWarrantyDepositTotal));
            list.get(0).setProjectWarrantyDepositPage(String.valueOf(projectWarrantyDepositPage));
            list.get(0).setRefundMoneyTotal(String.valueOf(refundMoneyTotal));
            list.get(0).setRefundMoneyPage(String.valueOf(refundMoneyPage));

            iPage.setRecords(list);
        }
        return new PageUtil<>(iPage);
    }

    @Override
    public PageUtil<SalesOpportunityVO> queryOpportunityAudit(IPage<SalesOpportunityVO> page, SalesOpportunityVO opportunityVO, List<SysUserEntity> userList, String token) {
        if (opportunityVO.getOrderByProp() != null) {
            if (opportunityVO.getOrderByProp().equals("createDataTime")) {
                opportunityVO.setOrderByProp("creationDate");
            }
            opportunityVO.setOrderByProp(StringUtils.camelToUnderline(opportunityVO.getOrderByProp()));
        }
        IPage<SalesOpportunityVO> iPage = salesOpportunityMapper.queryOpportunityAudit(page, opportunityVO);
//        List<SalesOpportunityVO> list = iPage.getRecords();
//        if (list != null && !list.isEmpty()) {
//            List<SalesOpportunityVO> voList = salesOpportunityMapper.queryOpportunity(opportunityVO, userList);
//            BigDecimal expectedAmountPage = new BigDecimal(0);
//            BigDecimal expectedAmountTotal = new BigDecimal(0);
//            for (SalesOpportunityVO item : list) {
//                expectedAmountPage = expectedAmountPage.add(new BigDecimal(item.getExpectedAmount().getValue()));
//            }
//            for (SalesOpportunityVO item : voList) {
//                expectedAmountTotal = expectedAmountTotal.add(new BigDecimal(item.getExpectedAmount().getValue()));
//            }
//            list.get(0).setExpectedAmountPage(String.valueOf(expectedAmountPage));
//            list.get(0).setExpectedAmountTotal(String.valueOf(expectedAmountTotal));
//            iPage.setRecords(list);
//        }
        return new PageUtil<>(iPage);
    }

    @Override
    public PageUtil<SalesOpportunityVO> queryOpportunityAuditOne(IPage<SalesOpportunityVO> page, SalesOpportunityVO opportunityVO, List<SysUserEntity> userList, String token) {
        if (opportunityVO.getOrderByProp() != null) {
            if (opportunityVO.getOrderByProp().equals("createDataTime")) {
                opportunityVO.setOrderByProp("creationDate");
            }
            opportunityVO.setOrderByProp(StringUtils.camelToUnderline(opportunityVO.getOrderByProp()));
        }
        IPage<SalesOpportunityVO> iPage = salesOpportunityMapper.queryOpportunityAuditOne(page, opportunityVO);
//        List<SalesOpportunityVO> list = iPage.getRecords();
//        if (list != null && !list.isEmpty()) {
//            List<SalesOpportunityVO> voList = salesOpportunityMapper.queryOpportunity(opportunityVO, userList);
//            BigDecimal expectedAmountPage = new BigDecimal(0);
//            BigDecimal expectedAmountTotal = new BigDecimal(0);
//            for (SalesOpportunityVO item : list) {
//                expectedAmountPage = expectedAmountPage.add(new BigDecimal(item.getExpectedAmount().getValue()));
//            }
//            for (SalesOpportunityVO item : voList) {
//                expectedAmountTotal = expectedAmountTotal.add(new BigDecimal(item.getExpectedAmount().getValue()));
//            }
//            list.get(0).setExpectedAmountPage(String.valueOf(expectedAmountPage));
//            list.get(0).setExpectedAmountTotal(String.valueOf(expectedAmountTotal));
//            iPage.setRecords(list);
//        }
        return new PageUtil<>(iPage);
    }

    @Override
    public PageUtil<SalesOpportunityVO> queryToDoList(IPage<SalesOpportunityVO> page, SalesOpportunityVO opportunityVO) {
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("机会状态变更审批流程");
        activitiVO.setProcessCode("opportunityStateChangeAudit");
        // 获取当前用户的待办信息
        ResponseAPI<List<ActivitiVO>> workFlowVoResponseAPI = workFlowService.getTasksByAuthorization(activitiVO);
        List<ActivitiVO> toDos = workFlowVoResponseAPI.getResult();
        if (toDos.isEmpty()) {
            return new PageUtil(new PageDTO());
        } else {
            if (opportunityVO.getOrderByProp() != null) {
                opportunityVO.setOrderByProp(StringUtils.camelToUnderline(opportunityVO.getOrderByProp()));
            }
            return new PageUtil(salesOpportunityMapper.queryToDoList(page, opportunityVO, toDos));
        }
    }

    public List<SalesOpportunityVO> queryOpportunity(SalesOpportunityVO opportunityVO, List<SysUserEntity> userList, String token) {
        if (opportunityVO.getOrderByProp() != null) {
            opportunityVO.setOrderByProp(StringUtils.camelToUnderline(opportunityVO.getOrderByProp()));
        }
        return salesOpportunityMapper.queryOpportunity(opportunityVO, userList);
    }

    @Override
    public List<SalesOpportunityVO> selectAllOpInfo(SalesOpportunityVO record) {
        return salesOpportunityMapper.selectAllOpInfo(record);
    }

    @Override
    public boolean updateByPrimaryKey(SalesOpportunityVO record) {
        // 转发人记录
        if (record.getSenderList() != null && !record.getSenderList().isEmpty()){
            TranspondEmailVO transpondEmailVO = new TranspondEmailVO();
            transpondEmailVO.setTodoType(Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
            transpondEmailVO.setTypeId(record.getOpportunityId());
            List<Integer> senderList = new ArrayList<>();
            for (SysUserEntity user:record.getSenderList()) {
                senderList.add(user.getUserId());
            }
            transpondEmailVO.setTranspondUseIdList(senderList);
            transpondEmailService.insertTranspondEmailInfoByType(transpondEmailVO);
        }
        return salesOpportunityMapper.updateByPrimaryKeySelective(record) == 1;
    }

    @Override
    public SalesOpportunityVO commitStateChangeToAudit(SalesOpportunityVO op, String token) {
        // 启动工作流
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("机会状态变更审批流程");
        activitiVO.setProcessCode("opportunityStateChangeAudit");
        activitiVO.setNextNodeParams("commercialSpecialist");
        // // 获取模块管理员第一人作为待办审批人
//        List<SysUserEntity> commercialSpecialist = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist");
//        SysUserEntity commercialSpecial = feginService.searchUserInfoByIds(commercialSpecialist.get(0).getUserId(), token).getResult();
//        List<SysUserEntity> presidentlist = dictionaryService.queryMenuUserIdsByCode("president");
//        SysUserEntity president = feginService.searchUserInfoByIds(presidentlist.get(0).getUserId(), token).getResult();
//        Map<String, Object> paramMap = new HashMap<>();
//        paramMap.put("commercialSpecialist", commercialSpecial.getAccount());
//        paramMap.put("president", president.getAccount());
//        activitiVO.setCustomParams(paramMap);
        SysUserEntity commercialSpecial = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        activitiVO.setNextNodeAssignee(commercialSpecial.getAccount());
        ActivitiVO workFlowResult = workFlowService.startMaxVersionProcessByDesignCodeCustomParams(activitiVO).getResult();
//        ActivitiVO workFlowResult = workFlowService.startProcessByDesignCodeVersionBatchCustomParams(activitiVO).getResult();
        ApprovalVO approval = approvalService.initApprovalAndLog(workFlowResult.getBusinessId(), Constants.OPPORTUNITY_AUDIT_TASK_TYPE,
                op.getReasonApplication(), "", -1, "");
        ApprovalVO approvalVO = approvalService.queryApprovalByAppID(approval.getApprovalId());
        // 记录工作流ID并进入审核状态，审核状态前端不允许编辑
        // 最后更新时间即为申请时间，最后修改人为申请人
        op.setBusinessId(approval.getApprovalId());
//        op.setAuditState(Constants.OPPORTUNITY_AUDITING);
        op.setLastUpdateBy(AuthUtils.getUserId());
        opportunityBackMapper.insertBackInfo(op.getOpportunityId());
        boolean updateSuccess = salesOpportunityMapper.startAudit(op) == 1;
        // 获取数据库中最新数据
        op = salesOpportunityMapper.selectByPrimaryKey(op.getOpportunityId());
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(op.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            op.setSenderList(senderList);
        }
        if (updateSuccess) {
//            List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("opportunity");
//            String copyForUserEmails = getCopyForUserEmails(copyUserIList);
            if (commercialSpecial.getUserId().equals(AuthUtils.getUserId())) {
                //跳过第一步审批
                this.approveStateChange(op, token, true);
            } else {
                approvalService.updateNextApproverByApprovalId(commercialSpecial.getUserId(), approval.getApprovalId());
                sendToDoMessage(op, approvalVO, null, commercialSpecial, token);
            }
        }

        // 返回最新机会
        return op;
    }

    @Override
    public boolean approveStateChange(SalesOpportunityVO op, String token, Boolean auto) {
//        Integer userId = AuthUtils.getUserId();
//        SysUserEntity commercialSpecial = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
//        SysUserEntity president = dictionaryService.queryMenuUserIdsByCode("president").get(0);
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        ApprovalVO approvalVO = approvalService.queryApprovalByAppID(op.getBusinessId());
        activitiVO.setBusinessId(approvalVO.getBusinessId());
        //获取当前所处节点
        ActivitiVO workFlowResult = workFlowService.getProcessNodeNameAndCode(activitiVO).getResult();
        //记录审批日志
        if (auto) {
            approvalService.insertApprovalLog(op.getBusinessId(), "通过", "系统判定跳过", op.getProcessComments());
        } else {
            approvalService.insertApprovalLog(op.getBusinessId(), "通过", "机会状态变更审批", op.getProcessComments());
        }
        if ("售后".equals(workFlowResult.getName())) {
            // 审批通过
            workFlowService.approvalProcessByBusinessId(activitiVO);
            approvalService.approved(null, op.getBusinessId());
            salesOpportunityMapper.updateByPrimaryKeySelective(op);
            SalesStageVO stageVO = stageMapper.queryStageInfo(op.getOpportunityId(), Constants.OPPORTUNITY_MODEL_ID).get(0);
            stageMapper.updateByPrimaryKeySelective(stageVO);
            sendApprovalMessage(op, approvalVO, token);
        } else {
            //总经理信息
            SysUserEntity president = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
            activitiVO.getCustomParams().put("afterSales", president.getAccount());
            //审批通过（使用动态入参传入下一审批人）
            workFlowService.approvalProcessCustomUserByBusinessId(activitiVO);
            //获取下一节点
            ActivitiVO nextWorkFlowResult = workFlowService.getProcessNodeNameAndCode(activitiVO).getResult();
            if (nextWorkFlowResult.getAssignee().equals(workFlowResult.getAssignee())) { //记录日志
                this.approveStateChange(op, token, true);
            } else {
                approvalService.updateNextApproverByApprovalId(president.getUserId(), approvalVO.getApprovalId());
                sendToDoMessage(op, approvalVO, null, president, token);
            }
        }
        return true;
    }

    @Override
    public boolean rejectStateChange(SalesOpportunityVO op, String token) {
//        Integer userId = AuthUtils.getUserId();
//        SysUserEntity commercialSpecial = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
//        SysUserEntity president = dictionaryService.queryMenuUserIdsByCode("president").get(0);
//        List<ApprovalLogVO> approvalLogVOS = approvalService.queryApprovalLogByAppID(op.getBusinessId());
        //获取上一人
//        ApprovalLogVO approvalLogVO = approvalLogVOS.get(approvalLogVOS.size() - 1);
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        ApprovalVO approvalVO = approvalService.queryApprovalByAppID(op.getBusinessId());
        activitiVO.setBusinessId(approvalVO.getBusinessId());
        // 删除实例，驳回至起点
        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(approvalVO.getCreator(), token);
        SysUserEntity user = res.getResult();
        workFlowService.deleteInstance(activitiVO);
        String title = "【系统通知】机会点信息 - 流程单审批驳回通知";
        String record = "您好，您申请的机会点信息审批已被驳回：";
        op.setOpportunityState(1);
        salesOpportunityMapper.updateByPrimaryKeySelective(op);
        Integer todoUserId = 0;
        sendRejectMessage(op, user, todoUserId, 1, title, record, approvalVO, token);
        approvalService.insertApprovalLog(op.getBusinessId(), "驳回", "机会状态变更审批", op.getProcessComments());
        return approvalService.approvalRejection(null, op.getBusinessId());
    }

    @Override
    public boolean logicDelete(Integer opId) {
        SalesOpportunityVO record = new SalesOpportunityVO();
        record.setOpportunityId(opId);
        record.setLastUpdateBy(AuthUtils.getUserId());
        return salesOpportunityMapper.logicDelete(record) == 1;
    }

    @Override
    public SalesOpportunityVO queryOpportunityById(Integer opId) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.selectByPrimaryKey(opId);
        List<SysUserEntity> list = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!list.isEmpty()) {
            opportunityVO.setSenderList(list);
        }
        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opId, Constants.OPPORTUNITY_MODEL_ID);
        if (fileRelationVOS.size() > 0) {
            opportunityVO.setMessageFileRelation(fileRelationVOS);
        }
        return opportunityVO;
    }

    public SalesOpportunityVO queryOpportunityAllById(Integer opId) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.selectByPrimaryKey(opId);
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            opportunityVO.setSenderList(senderList);
        }
//        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opId, Constants.OPPORTUNITY_MODEL_ID);
        opportunityVO.setMessageFileRelation(salesOpportunityMapper.selectDocymentsByOppid(opId));
        //查询采购单
        List<PurchaseOrderVO> purchaseOrderVOS = purchaseOrdeService.queryPurchaseOrdersByOpId(opId);
        for (PurchaseOrderVO pvo : purchaseOrderVOS) {
            List<Integer> ids = new ArrayList<>();
            ids.add(pvo.getPurchaseId());
            pvo.setReceiptRecords(receiptRecordsMapper.getReceiptRecordsByPurchaseOrderIds(ids));
            pvo.setPaymentRecords(paymentRecordsMapper.getPayRecordsByPurchaseOrderIds(ids));
            pvo.setPaymentRequests(paymentRequestMapper.getPayRequestByPurchaseOrderIds(ids));
            List<RefundRecordsVO> refundRecordsByPurchaseIds = refundRecordsMapper.getRefundRecordsByPurchaseIds(ids);
            for (RefundRecordsVO refundRecordsByPurchaseId : refundRecordsByPurchaseIds) {
                String stringBuilder = transpondEmailService.selectTranspondNameStr(refundRecordsByPurchaseId.getApprovalId());
                if (stringBuilder != null || stringBuilder.length() != 0){
                    refundRecordsByPurchaseId.setTranspondUseListStr(stringBuilder);
                }
            }
            pvo.setRefundRecords(refundRecordsByPurchaseIds);

        }
        opportunityVO.getAllThings().addAll(purchaseOrderVOS);
        opportunityVO.setPurchaseOrders(purchaseOrderVOS);

        //内部采购
        List<PurchaseOrderVO> inPurchaseOrderVOS = internalPurchaseService.queryPurchaseOrdersByOpId(opId);
        opportunityVO.getAllThings().addAll(inPurchaseOrderVOS);
        opportunityVO.setInPurchaseOrders(inPurchaseOrderVOS);

        if (purchaseOrderVOS != null && purchaseOrderVOS.size() > 0) {
            List<Integer> list = new ArrayList<>();
            for (PurchaseOrderVO purchaseOrderVO : purchaseOrderVOS) {
                list.add(purchaseOrderVO.getPurchaseId());
            }
            List<PaymentPlan> paymentPlans = paymentPlanMapper.getPayPlanListBypurchaseOrderIds(list);
            List<PaymentRecords> paymentRecords = paymentRecordsMapper.getPayRecordsByPurchaseOrderIds(list);
            List<ReceiptRecords> receiptRecords = receiptRecordsMapper.getReceiptRecordsByPurchaseOrderIds(list);
            List<PaymentRequest> paymentRequests = paymentRequestMapper.getPayRequestByPurchaseOrderIds(list);
            List<RefundRecordsVO> recordsVOS = refundRecordsMapper.getRefundRecordsByPurchaseIds(list);
            for (RefundRecordsVO refundRecordsByPurchaseId : recordsVOS) {
                String stringBuilder = transpondEmailService.selectTranspondNameStr(refundRecordsByPurchaseId.getApprovalId());
                if (stringBuilder != null || stringBuilder.length() != 0){
                    refundRecordsByPurchaseId.setTranspondUseListStr(stringBuilder);
                }
            }
            opportunityVO.setPaymentPlans(paymentPlans);
            opportunityVO.setPaymentRecords(paymentRecords);
            opportunityVO.setReceiptRecords(receiptRecords);
            opportunityVO.setPaymentRequests(paymentRequests);
            opportunityVO.setRefundRecords(recordsVOS);
            opportunityVO.getAllThings().addAll(paymentRecords);
            opportunityVO.getAllThings().addAll(paymentPlans);
            opportunityVO.getAllThings().addAll(receiptRecords);
            opportunityVO.getAllThings().addAll(paymentRequests);
            opportunityVO.getAllThings().addAll(recordsVOS);


        }
        //opportunityVO.setPurchaseOrders(purchaseOrdeService.queryPurchaseOrdersByOpId(opId));
        //获取全部退款信息
//        List<RefundRecordsVO> recordsVOS = refundRecordsMapper.selectRefundByOpId(opId);
//
//        opportunityVO.getAllThings().addAll(recordsVOS);
        return opportunityVO;
    }

    @Override
    public void createRecord(SalesOpportunityVO oldOp, SalesOpportunityVO newOp, String token) {
//        Integer userId = AuthUtils.getUserId();
        StringBuffer sb = new StringBuffer();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        JSONObject userObject = feginService.getUserInfo(token);
        // 获取机会阶段状态字典
        String stateDictCode = "opportunityStage";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
        DecimalFormat formatter = new DecimalFormat("#,##0.00");
        sb.append(compare("机会名称", oldOp.getOpportunityTheme(), newOp.getOpportunityTheme()))
                .append(compare("负责人", (String) getUserNameById(userObject).get(oldOp.getOwner()), (String) getUserNameById(userObject).get(newOp.getOwner())))
                .append(compare("客户名称", oldOp.getCustomerName(), newOp.getCustomerName()))
                .append(compare("联系人", oldOp.getCustomerContact(), newOp.getCustomerContact()))
                .append(compare("联系方式", oldOp.getCustomerPhone(), newOp.getCustomerPhone()))
                .append(compare("可能性", oldOp.getOpportunityPossibility() + "%", newOp.getOpportunityPossibility() + "%"))
                .append(compare("预期金额", formatter.format(Double.valueOf(oldOp.getExpectedAmount().getValue())), formatter.format(Double.valueOf(newOp.getExpectedAmount().getValue()))))
                .append(compare("发现时间", dateFormat.format(oldOp.getDiscoveryTime()), dateFormat.format(newOp.getDiscoveryTime())))
                .append(compare("阶段", (String) getCRMDictionaryNameByCode("opportunityStage", listMap).get(oldOp.getStageStateId().toString()), (String) getCRMDictionaryNameByCode("opportunityStage", listMap).get(newOp.getStageStateId().toString())))
                .append(compare("预计签单", dateFormat.format(oldOp.getExpectedSigningDate()), dateFormat.format(newOp.getExpectedSigningDate())));
        SalesChangeVO salesChangeVO = new SalesChangeVO();
        salesChangeVO.setCreator(AuthUtils.getUserId());
        salesChangeVO.setSalesRelationId(oldOp.getOpportunityId());
        salesChangeVO.setChangeClass(Constants.OPPORTUNITY_MODEL_ID);
        if (sb.length() > 0) {
            // 消除最后的逗号
            sb.replace(sb.length() - 1, sb.length(), "");
            salesChangeVO.setChangeInfo(sb.toString());
            salesChangeService.insert(salesChangeVO);
        }
    }

    public String compare(String pre, String oldValue, String newValue) {
        if (!Objects.equals(oldValue, newValue)) {
            return pre + "从【" + oldValue + "】变更为【" + newValue + "】，";
        }
        return "";
    }

    // 给审批人发送待办邮件
    private void sendToDoMessage(SalesOpportunityVO op, ApprovalVO approvalVO, String copyForUserEmails, SysUserEntity todoUser, String token) {
//        Integer userId = AuthUtils.getUserId();
        // 获取机会状态字典
        String stateDictCode = "opportunityState";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
//        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
//        JSONObject userObject = feginService.getUserInfo(token);
        // 发送邮件
//        String title = "【系统通知】机会点信息 - 流程单审批通知";
//        String msg = "<div><p>" + "尊敬的" + todoUser.getLoginName() + "：</p></div>" +
//                "<div><p style='text-indent: 2em'>您好，您有一个新的机会点信息审批需要处理：</p></div>" +
//                "<div><p style='text-indent: 2em'>机会编号：" + op.getOpportunityNumber() + "</p></div>" +
//                "<div><p style='text-indent: 2em'>机会名称：" + op.getOpportunityTheme() + "</p></div>" +
//                "<div><p style='text-indent: 2em'>机会状态：" + getCRMDictionaryNameByCode("opportunityState", listMap).get(op.getOpportunityState().toString()) + "</p></div>" +
//                "<div><p style='text-indent: 2em'>申请人：" + getUserNameById(userObject).get(op.getLastUpdateBy()) + " / " + getUserAccountById(userObject).get(op.getLastUpdateBy()) + "</p></div>" +
//                "<div><p style='text-indent: 2em'>申请时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(op.getLastUpdateTime()) + "</p></div>" +
//                "<div><p style='text-indent: 2em'>申请原因：" + (op.getReasonApplication() == null ? "无" : op.getReasonApplication()) + "</p></div>" +
//                "<div><p style='text-indent: 2em'>系统审批路径：客户关系管理系统 - 待办事项 - 待办审批 " +
//                "<a href='" + webSitUrl + "/?m=crm&p=crmtodoItems&me=todoApprovalPath'>进入</a></p></div>" +
//                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
//                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
//        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(todoUser.getEmail(), copyForUserEmails, title, msg, token));
        // 调用通知接口
//        Timestamp now = new Timestamp(System.currentTimeMillis());
        CompletableFuture.runAsync(() ->
                NoticUtils.pushNotic(op.getBusinessId(), approvalVO.getCreateDataTime(),
                        approvalVO.getCreator(), 0, Constants.OPPORTUNITY_AUDIT_TASK_TYPE, todoUser.getUserId(), token));
    }

    // 发送驳回的系统邮件和系统通知
    private void sendRejectMessage(SalesOpportunityVO op, SysUserEntity user, Integer todoUserId, Integer workState, String title, String record, ApprovalVO approval, String token) {
        //发送邮件
//        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(todoUserId, token);
//        SysUserEntity user = res.getResult();
        // 获取机会阶段状态字典
        String stateDictCode = "opportunityStage";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
        String msg;
        //发送邮件
//        if (workState == 1) {
        msg = "<div><p>" + "尊敬的" + user.getLoginName() + "：</p></div>" +
                "<div><p style='text-indent: 2em'>" + record + "</p></div>" +
                "<div><p style='text-indent: 2em'>机会编号：" + op.getOpportunityNumber() + "</p></div>" +
                "<div><p style='text-indent: 2em'>机会名称：" + op.getOpportunityTheme() + "</p></div>" +
                "<div><p style='text-indent: 2em'>预期金额：" + op.getExpectedAmount().getValue() + "元</p></div>" +
                "<div><p style='text-indent: 2em'>发现时间：" + new SimpleDateFormat("yyyy-MM-dd").format(op.getDiscoveryTime()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>预计签单：" + new SimpleDateFormat("yyyy-MM-dd").format(op.getExpectedSigningDate()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>可能性：" + op.getOpportunityPossibility() + "%</p></div>" +
                "<div><p style='text-indent: 2em'>阶段：" + getCRMDictionaryNameByCode("opportunityStage", listMap).get(op.getStageStateId().toString()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>审批意见：" + (op.getProcessComments() == null ? "无" : op.getProcessComments()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>审批时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Timestamp(System.currentTimeMillis())) + "</p></div>" +
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 机会信息管理 - 机会信息 " +
                "<a href='" + webSitUrl + "/?m=crm&p=salesManage&me=salesOpportunity'>进入</a></p></div>" +
                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(user.getEmail(), null, title, msg, token));
        // 调用通知接口，消除通知
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(op.getBusinessId(), approval.getCreateDataTime(), approval.getCreator(),
                workState, Constants.OPPORTUNITY_AUDIT_TASK_TYPE, todoUserId, token));
    }

    // 发送审批通过系统邮件
    private void sendApprovalMessage(SalesOpportunityVO op, ApprovalVO approval, String token) {
        //发送邮件
        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(approval.getCreator(), token);
        SysUserEntity user = res.getResult();
        // 获取机会阶段状态字典
        String stateDictCode = "opportunityStage";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
        //发送邮件
        String title = "【系统通知】机会点信息 - 流程单审批通过通知";
        String msg = "<div><p>" + "尊敬的" + user.getLoginName() + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，您申请的机会点信息审批已经通过：</p></div>" +
                "<div><p style='text-indent: 2em'>机会编号：" + op.getOpportunityNumber() + "</p></div>" +
                "<div><p style='text-indent: 2em'>机会名称：" + op.getOpportunityTheme() + "</p></div>" +
                "<div><p style='text-indent: 2em'>预期金额：" + op.getExpectedAmount().getValue() + "元</p></div>" +
                "<div><p style='text-indent: 2em'>发现时间：" + new SimpleDateFormat("yyyy-MM-dd").format(op.getDiscoveryTime()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>预计签单：" + new SimpleDateFormat("yyyy-MM-dd").format(op.getExpectedSigningDate()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>可能性：" + op.getOpportunityPossibility() + "%</p></div>" +
                "<div><p style='text-indent: 2em'>阶段：" + getCRMDictionaryNameByCode("opportunityStage", listMap).get(op.getStageStateId().toString()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>审批时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Timestamp(System.currentTimeMillis())) + "</p></div>" +
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 机会信息管理 - 机会信息 " +
                "<a href='" + webSitUrl + "/?m=crm&p=salesManage&me=salesOpportunity'>进入</a></p></div>" +
                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("opportunity");
        String copyForUserEmails = getCopyForUserEmails(copyUserIList);
        String transpondEmails = transpondEmailService.selectTranspondEmailStrByType(op.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if(!transpondEmails.isEmpty()){
            copyForUserEmails = copyForUserEmails + "," + transpondEmails;
        }
        String finalCopyForUserEmails = copyForUserEmails;
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(user.getEmail(), finalCopyForUserEmails, title, msg, token));
        // 调用通知接口，消除通知
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(op.getBusinessId(), approval.getCreateDataTime(), approval.getCreator(),
                1, Constants.OPPORTUNITY_AUDIT_TASK_TYPE, 0, token));
    }

    // 获取抄送用户邮箱，逗号分隔
    private String getCopyForUserEmail(SalesOpportunityVO record, String token) {
        // 发送邮件
        String copyFor = record.getCopyFor();       // 抄送人
        StringBuilder copyForUserEmails = new StringBuilder();              // 抄送人邮箱
        // 获取所有用户信息
        List<SysUserEntity> allUser = feginService.getUserIgnoreFlag(token).getResult();
        // 拼接抄送人邮箱
        if (copyFor != null && copyFor.length() > 0) {
            String[] userIds = copyFor.split(",");      // 获取所有抄送人ID
            List<SysUserEntity> copyForUsers = new ArrayList<>();

            for (String userId : userIds) {     // 根据抄送人ID过滤抄送用户对象
                for (SysUserEntity user : allUser) {
                    if (user.getUserId() == Integer.parseInt(userId)) {
                        copyForUsers.add(user);
                    }
                }
            }

            if (!copyForUsers.isEmpty()) {      // 根据抄送用户对象拼接抄送人邮箱
                for (SysUserEntity copyForUser : copyForUsers) {
                    copyForUserEmails.append(copyForUser.getEmail()).append(",");
                }
                // 移除最后一个逗号
                copyForUserEmails.replace(copyForUserEmails.lastIndexOf(","), copyForUserEmails.length(), "");
            }
        }
        return copyForUserEmails.toString();
    }

    private String getCopyForUserEmails(List<SysUserEntity> userList) {
        StringBuilder copyForUserEmails = new StringBuilder();           // 抄送人邮箱
        if (!userList.isEmpty()) {      // 根据抄送用户对象拼接抄送人邮箱
            for (SysUserEntity copyForUser : userList) {
                copyForUserEmails.append(copyForUser.getEmail()).append(",");
            }
            // 移除最后一个逗号
            copyForUserEmails.replace(copyForUserEmails.lastIndexOf(","), copyForUserEmails.length(), "");
        }
        return copyForUserEmails.toString();
    }

    private Map getUserNameById(JSONObject jsonObject) {
        List<Map> dataDictionaryArray = (List) jsonObject.get("result");
        Map<Integer, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put((Integer) item.get("userId"), (String) item.get("loginName"));
            }
            return map;
        }
        return null;
    }

    private Map getUserAccountById(JSONObject jsonObject) {
        List<Map> dataDictionaryArray = (List) jsonObject.get("result");
        Map<Integer, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put((Integer) item.get("userId"), (String) item.get("account"));
            }
            return map;
        }
        return null;
    }

    private Map getDictionaryNameByCode(String itemCode, JSONObject jsonObject) {
        LinkedHashMap linkedHashMap = (LinkedHashMap) jsonObject.get("result");
        List<Map> dataDictionaryArray = (List) linkedHashMap.get(itemCode);
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put(item.get("itemCode").toString(), item.get("itemName").toString());
            }
            return map;
        }
        return null;
    }

    private Map getDictionaryNameByCode(String itemCode, Map<String, List<DictionaryLookupItemVO>> listMap) {
        List<DictionaryLookupItemVO> dataDictionaryArray = listMap.get(itemCode);
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (DictionaryLookupItemVO item : dataDictionaryArray) {
                map.put(item.getItemCode(), item.getItemName());
            }
            return map;
        }
        return null;
    }

    private Map getCRMDictionaryNameByCode(String itemCode, Map listMap) {
//        LinkedHashMap linkedHashMap = (LinkedHashMap) listMap.get("result");
        List<DictionaryLookupItemVO> dataDictionaryArray = (List) listMap.get(itemCode);
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (DictionaryLookupItemVO item : dataDictionaryArray) {
                map.put(item.getItemCode(), item.getItemName());
            }
            return map;
        }
        return null;
    }

    @Override
    public SalesOpportunityVO queryOpportunityByBusinessId(Integer workId) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.queryOpportunityByBusinessId(workId);
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            opportunityVO.setSenderList(senderList);
        }
        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opportunityVO.getOpportunityId(), Constants.OPPORTUNITY_MODEL_ID);
        if (!fileRelationVOS.isEmpty()) {
            opportunityVO.setMessageFileRelation(fileRelationVOS);
        }
        return opportunityVO;
    }

    @Override
    public SalesOpportunityVO queryHistoryOpportunityByApprovalId(Integer workId) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.queryHistoryOpportunityByApprovalId(workId);
        if (Objects.isNull(opportunityVO)) {
            return queryOpportunityByBusinessId(workId);
        }
        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opportunityVO.getOpportunityId(), Constants.OPPORTUNITY_MODEL_ID);
        if (!fileRelationVOS.isEmpty()) {
            opportunityVO.setMessageFileRelation(fileRelationVOS);
        }
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            opportunityVO.setSenderList(senderList);
        }
        return opportunityVO;
    }

    public void opportunityWithdrawal(ApprovalVO approval, String token) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.queryOpportunityByBusinessId(approval.getApprovalId());
        opportunityVO.setOpportunityState(1);
        salesOpportunityMapper.updateByPrimaryKeySelective(opportunityVO);
    }

    /**
     * 更具ID获取机会负责人信息
     *
     * @return
     */
    public SysUserEntity queryOpportunityHeadByProjectId(Integer opportunityId, String token) {
        Integer projectPrincipalId = salesOpportunityMapper.queryOpportunityHeadByProjectId(opportunityId);
        ResponseAPI<SysUserEntity> responseAPI = feginService.searchUserInfoById(projectPrincipalId, token);
        return responseAPI.getResult();
    }

    @Override
    public SalesOpportunityVO queryOpportunityByApprovalId(Integer approvalId) {
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.queryOpportunityByApprovalId(approvalId);
        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opportunityVO.getOpportunityId(), Constants.OPPORTUNITY_MODEL_ID);
        if (!fileRelationVOS.isEmpty()) {
            opportunityVO.setMessageFileRelation(fileRelationVOS);
        }
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            opportunityVO.setSenderList(senderList);
        }
        return opportunityVO;
    }

    @Override
    public SalesOpportunityVO queryOpportunityHistoryByApprovalId(Integer approvalId){
        SalesOpportunityVO opportunityVO = salesOpportunityMapper.queryOpportunityByApprovalId(approvalId);
        if(opportunityVO == null){
            opportunityVO = salesOpportunityMapper.queryOpportunityHistoryByApprovalId(approvalId);
        }
        if(opportunityVO == null){
            return new SalesOpportunityVO();
        }
        List<SalesFileRelationVO> fileRelationVOS = fileRelationMapper.queryFileInfoList(opportunityVO.getOpportunityId(), Constants.OPPORTUNITY_MODEL_ID);
        if (!fileRelationVOS.isEmpty()) {
            opportunityVO.setMessageFileRelation(fileRelationVOS);
        }
        List<SysUserEntity> senderList = transpondEmailService.selectTranspondEmailByType(opportunityVO.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if (!senderList.isEmpty()) {
            opportunityVO.setSenderList(senderList);
        }
        return opportunityVO;
    }

    @Override
    public boolean approveCreateOp(SalesOpportunityVO record, String token, boolean auto) {
        Integer ownerId = record.getOwner();
        //record = salesOpportunityMapper.selectByPrimaryKey(record.getOpportunityId());
        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(ownerId, token);
        SysUserEntity user = res.getResult();
        List<SysUserEntity> allUser = salesProjectManageMapper.getUserInformation();
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        ApprovalVO approvalVO = approvalService.queryApprovalByAppID(record.getApprovalId());
        activitiVO.setBusinessId(approvalVO.getBusinessId());
        //获取当前所处节点
        SysUserEntity askUser = feginService.searchUserInfoById(approvalVO.getCreator(),token).getResult();
        ResponseAPI<ActivitiVO> processNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);
        //通过才能看到并使用改机会
        salesOpportunityMapper.updateDeleteAudit(record);
        String title;
        String msg;
        if (auto) {
            approvalService.insertApprovalLog(approvalVO.getApprovalId(), "通过", "系统判定跳过", record.getProcessComments());
        } else {
            approvalService.insertApprovalLog(approvalVO.getApprovalId(), "通过", "机会信息创建审批", record.getProcessComments());
        }
        if( "售后审批".equals(processNodeNameAndCode.getResult().getName()) ) {
            user=askUser;
            workFlowFeginService.approvalProcessByBusinessId(activitiVO);
            approvalService.approved(null,record.getApprovalId());
        }
        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("opportunity");
        String copyForUserEmails = getCopyForUserEmails(copyUserIList);
        String transpondEmails = transpondEmailService.selectTranspondEmailStrByType(record.getOpportunityId(),Constants.OPPORTUNITY_AUDIT_TASK_TYPE);
        if(!transpondEmails.isEmpty()){
            copyForUserEmails = copyForUserEmails + "," + transpondEmails;
        }
        // 获取机会阶段状态字典
        String stateDictCode = "opportunityStage";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
        title = "【系统通知】机会点信息创建 - 流程单提醒通知";
        msg = "<div><p>" + "尊敬的" + user.getLoginName() + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，您有一个新的机会点创建成功：</p></div>" +
                "<div><p style='text-indent: 2em'>机会编号：" + record.getOpportunityNumber() + "</p></div>" +
                "<div><p style='text-indent: 2em'>机会名称：" + record.getOpportunityTheme() + "</p></div>" +
                "<div><p style='text-indent: 2em'>预期金额：" + record.getExpectedAmount().getValue() + "元</p></div>" +
                "<div><p style='text-indent: 2em'>发现时间：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getDiscoveryTime()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>预计签单：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getExpectedSigningDate()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>可能性：" + record.getOpportunityPossibility() + "%</p></div>" +
                "<div><p style='text-indent: 2em'>阶段：" + getCRMDictionaryNameByCode("opportunityStage", listMap).get(record.getStageStateId().toString()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>审批时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Timestamp(System.currentTimeMillis())) + "</p></div>" +
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 机会信息管理 - 机会信息 " +
                "<a href='" + webSitUrl + "/?m=crm&p=salesManage&me=salesOpportunity'>进入</a></p></div>" +
                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        String ownerEmail = allUser.stream().filter(p -> Objects.equals(p.getUserId(), approvalVO.getCreator())).toList().get(0).getEmail();
        String finalCopyForUserEmails = copyForUserEmails;
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(ownerEmail, finalCopyForUserEmails, title, msg, token));
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(record.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                approvalVO.getCreator(),1,45,0,token));
        // 保存机会时会插入一条阶段变更记录
        SalesStageVO salesStageVO = new SalesStageVO();
        salesStageVO.setStageClass(Constants.OPPORTUNITY_MODEL_ID);
        salesStageVO.setSalesRelationId(record.getOpportunityId());
        salesStageVO.setCreator(record.getCreator());
        salesStageVO.setCreateDataTime(record.getStageUpdateTime());
        salesStageVO.setStageStateId(record.getStageStateId());
        int insertSt = stageMapper.insert(salesStageVO);
        if(insertSt >0){
            return true;
        }else{
            return false;
        }

    }

    @Override
    public boolean rejectCreateOp(SalesOpportunityVO record, String token) {
        Integer ownerId = record.getOwner();
        //record = salesOpportunityMapper.selectByPrimaryKey(record.getOpportunityId());
        ResponseAPI<SysUserEntity> res = feginService.searchUserInfoByIds(ownerId, token);
        SysUserEntity user = res.getResult();
//        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("opportunity");
//        String copyForUserEmails = getCopyForUserEmails(copyUserIList);
        List<SysUserEntity> allUser = salesProjectManageMapper.getUserInformation();
        ApprovalVO approval = approvalService.queryApprovalByAppID(record.getApprovalId());
        approvalService.insertApprovalLog(approval.getApprovalId(), "驳回", "机会信息创建审批", record.getProcessComments());
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        workFlowFeginService.deleteInstance(activitiVO);
        salesOpportunityMapper.logicDeleteAudit(record);
        approvalService.approvalRejection(null,record.getApprovalId());
        // 获取机会阶段状态字典
        String stateDictCode = "opportunityStage";
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add(stateDictCode);
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, dictCodes);
        String title = "【系统通知】机会点信息创建 - 流程审批驳回通知";
        String msg = "<div><p>" + "尊敬的" + user.getLoginName() + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，您有一个新的机会点创建失败：</p></div>" +
                "<div><p style='text-indent: 2em'>机会编号：" + record.getOpportunityNumber() + "</p></div>" +
                "<div><p style='text-indent: 2em'>机会名称：" + record.getOpportunityTheme() + "</p></div>" +
                "<div><p style='text-indent: 2em'>预期金额：" + record.getExpectedAmount().getValue() + "元</p></div>" +
                "<div><p style='text-indent: 2em'>发现时间：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getDiscoveryTime()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>预计签单：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getExpectedSigningDate()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>可能性：" + record.getOpportunityPossibility() + "%</p></div>" +
                "<div><p style='text-indent: 2em'>阶段：" + getCRMDictionaryNameByCode("opportunityStage", listMap).get(record.getStageStateId().toString()) + "</p></div>" +
                "<div><p style='text-indent: 2em'>审批时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Timestamp(System.currentTimeMillis())) + "</p></div>" +
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 机会信息管理 - 机会信息 " +
                "<a href='" + webSitUrl + "/?m=crm&p=salesManage&me=salesOpportunity'>进入</a></p></div>" +
                "<div><p style='text-indent: 2em'>谢谢！</p></div>" +
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        String ownerEmail = allUser.stream().filter(p -> Objects.equals(p.getUserId(), approval.getCreator())).toList().get(0).getEmail();
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(ownerEmail, null, title, msg, token));
        Integer userId = AuthUtils.getUserId();
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(record.getApprovalId(), approval.getCreateDataTime(),
                userId,1,45,0,token));
        return true;
    }

    @Override
    public int transforPrincipal(Integer userId, List<SalesOpportunityVO> voList, String token) {
        if (!voList.isEmpty()) {
            //同时更新项目、机会责任人
            salesOpportunityMapper.transforPrincipalProject(userId, voList);
            return salesOpportunityMapper.transforPrincipal(userId, voList);
        }
        return 0;
    }


    /**
     * 开启审批流程
     * @return
     */
    private Integer startSaveOpportunityApproval(){
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("创建机会审批");
        activitiVO.setProcessCode("create_opportunity_approval");
        activitiVO.setNextNodeParams("afterSales");
        SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
        activitiVO.setNextNodeAssignee(business.getAccount());
//        HashMap<String,Object> customParams = new HashMap<>();
//        SysUserEntity president = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
//        customParams.put("commercialSpecialist",president.getAccount());
//        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
//        customParams.put("finance",finance.getAccount());
//        SysUserEntity afterSales = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
//        customParams.put("afterSales",afterSales.getAccount());
//        activitiVO.setCustomParams(customParams);
        ResponseAPI<ActivitiVO> responseAPI = workFlowFeginService.startMaxVersionProcessByDesignCodeCustomParams(activitiVO);
        return responseAPI.getResult().getBusinessId();
    }

    void exportOpportunityInfoExcel(HttpServletResponse response, List<SalesOpportunityVO> list) throws IOException, IntrospectionException, InvocationTargetException, IllegalAccessException {
        List<Map<String,Object>> tableConfigList = purchaseOrdeMapper.queryRefundShowTableConfig("crm", "salesOpportunity");
        LinkedHashMap<String, DynamicExcelData> nameMap = new LinkedHashMap<>(0,1.6f,true);
        for (int i = 0; i < tableConfigList.size(); i++) {
            Map item = tableConfigList.get(i);
            String name = String.valueOf(item.get("prop"));
            if ("owner".equals(name)) {  // 责任人特殊处理，字段替换
                name = "ownerName";
            } else if ("creator".equals(name)) {  // 创建者特殊处理，字段替换
                name = "creatorName";
            } else if ("opportunityPossibility".equals(name)) {  // 可能性特殊处理，字段替换
                name = "opportunityPossibilityPercentage";
            } else if ("stageStateId".equals(name)) {  // 阶段特殊处理，字段替换
                name = "stageStateName";
            } else if ("opportunityState".equals(name)) {  // 阶段特殊处理，字段替换
                name = "opportunityStateName";
            } else if ("createDataTime".equals(name)) {  // 阶段特殊处理，字段替换
                name = "stageUpdateTime";
            } else if ("auditState".equals(name)) {  // 审核状态名殊处理，字段替换
                name = "auditStateName";
            } else if ("projectDifferentId".equals(name)) {  // 项目区分名称处理，字段替换
                name = "projectDifferentName";
            } else if ("projectClasses".equals(name)) {  // 项目类别名称处理，字段替换
                name = "projectClassesName";
            } else if ("projectType".equals(name)) {  // 项目类型名称处理，字段替换
                name = "projectTypeName";
            } else if ("projectState".equals(name)) {  // 项目状态名称处理，字段替换
                name = "projectStateName";
            } else if ("auditStateLast".equals(name)) {  // 终验审批状态名称处理，字段替换
                name = "auditStateLastName";
            } else if ("approveStateFirst".equals(name)) {  // 初验审批状态名称处理，字段替换
                name = "approveStateFirstName";
            } else if ("warranty".equals(name)) {  // 初验审批状态名称处理，字段替换
                name = "warrantyName";
            }
            nameMap.put(name, new DynamicExcelData(String.valueOf(item.get("label")), null));
        }

        String[] arr = {"stageUpdateTime"};  // 长时间格式化，默认短时间格式
        List<Map<String, Object>> dataList = getDataList(list, Arrays.asList(arr));
        dynamicExport(response,nameMap, dataList,"项目信息",  null, false, null);
    }

    private Map getUserNameMap(JSONObject jsonObject) {
        List<Map> dataDictionaryArray = (List) jsonObject.get("result");
        Map<Integer, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put((Integer) item.get("userId"), item.get("loginName") + " / " + item.get("account"));
            }
            return map;
        }
        return null;
    }
}
